<template>
  <div class="role-definition">
    <TopNavigation :showOrganizationSection="false" />
    <div class="page-header">
      <h2>角色定义</h2>
    </div>

    <div class="card">
      <div class="toolbar">
        <div class="search-container">
          <div class="input-group">
            <input type="text" class="input" placeholder="搜索角色名称" v-model="searchKeyword" @keyup.enter="searchRoles" />
            <button class="button--submit" @click="searchRoles">
              搜索
            </button>
          </div>
        </div>
        <button class="btn btn-primary" @click="showAddModal">添加角色</button>
      </div>

      <div class="table-container">
        <!-- 加载状态 -->
        <div v-if="loading" class="loading-state">
          <div class="spinner"></div>
          <span>加载中...</span>
        </div>

        <!-- 错误提示 -->
        <div v-else-if="error" class="error-state">
          <div class="error-icon"></div>
          <span>{{ error }}</span>
        </div>
        <!-- 角色卡片展示 -->
        <div class="roles-grid">
          <div v-for="role in paginatedRoles" :key="role.id" class="role-card">
            <div class="role-header">
              <div class="role-title-section">
                <h3 class="role-name">{{ role.roleName }}</h3>
                <span class="config-name">{{ role.configName || '未配置' }}</span>
              </div>
              <div class="role-header-right">
                <div class="role-status">
                  <span :class="['status-badge', role.isActive ? 'status-active' : 'status-inactive']">
                    {{ role.isActive ? '激活' : '禁用' }}
                  </span>
                </div>
                <div class="role-actions">
                  <button class="edit-btn" @click="showEditModal(role)" title="编辑角色">
                    ✏️
                  </button>
                  <button class="delete-btn" @click="deleteRole(role.id)" title="删除角色">
                    🗑️
                  </button>
                </div>
              </div>
            </div>

            <div class="role-content">
              <div class="role-description-section">
                <div class="section-title">角色描述</div>
                <div class="role-description">{{ role.roleDescription || '暂无描述' }}</div>
              </div>

              <div class="field-config-section">
                <div class="section-title">字段配置</div>
                <div class="field-display">
                  <!-- 动态显示字段配置 -->
                  <div
                    v-if="getPrioritiesFromString(role.fieldPriorities).length > 0 || getFieldsFromConfig(role.fieldConfig).length > 0"
                    class="field-tags" :ref="`fieldTags-${role.id}`">
                    <span v-for="(field, index) in getVisibleFields(role)" :key="field" class="field-tag">
                      <span v-if="getPrioritiesFromString(role.fieldPriorities).length > 0" class="priority-number">{{
                        index + 1 }}</span>
                      <i class="field-icon">🏷️</i>{{ field }}
                    </span>
                    <span v-if="shouldShowFieldMoreIndicator(role)" class="more-indicator"
                      @mouseenter="showFieldTooltip($event, role)" @mouseleave="hideTooltip">
                      +{{ getHiddenFieldCount(role) }}
                    </span>
                  </div>
                  <span v-else class="empty-value">未配置</span>
                  <div v-if="getPrioritiesFromString(role.fieldPriorities).length > 0" class="field-summary">
                    共 {{ getPrioritiesFromString(role.fieldPriorities).length }} 个字段
                  </div>
                  <div v-else-if="getFieldsFromConfig(role.fieldConfig).length > 0" class="field-summary">
                    共 {{ getFieldsFromConfig(role.fieldConfig).length }} 个字段
                  </div>
                </div>
              </div>

              <div class="department-section">
                <div class="section-title">部门分配</div>
                <div class="department-display">
                  <div v-if="getDepartmentsFromString(role.departmentAssignments).length > 0" class="department-tags"
                    :ref="`deptTags-${role.id}`">
                    <span v-for="(dept, index) in getVisibleDepartments(role)" :key="dept" class="department-tag">
                      <i class="dept-icon">🏢</i>{{ dept }}
                    </span>
                    <span v-if="shouldShowMoreIndicator(role)" class="more-indicator"
                      @mouseenter="showDepartmentTooltip($event, role)" @mouseleave="hideTooltip">
                      +{{ getHiddenDepartmentCount(role) }}
                    </span>
                  </div>
                  <span v-else class="empty-value">未分配</span>
                  <div v-if="getDepartmentsFromString(role.departmentAssignments).length > 0" class="dept-summary">
                    共 {{ getDepartmentsFromString(role.departmentAssignments).length }} 个部门
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>

        <!-- 空状态提示 -->
        <div v-if="!loading && !error && paginatedRoles.length === 0" class="empty-state">
          暂无角色数据
        </div>

        <!-- 分页 -->
        <div v-if="!loading && paginatedRoles.length > 0" class="pagination-container">
          <div class="pagination">
            <button class="btn btn-default" :disabled="page === 1" @click="onPageChange(page - 1)">上一页</button>
            <span class="page-info">第 {{ page }} 页 / 共 {{ Math.ceil(totalItems / pageSize) }} 页</span>
            <button class="btn btn-default" :disabled="page >= Math.ceil(totalItems / pageSize)"
              @click="onPageChange(page + 1)">下一页</button>
            <div class="page-size-selector">
              <span>每页显示:</span>
              <select class="select" v-model="pageSize" @change="onPageSizeChange">
                <option :value="5">5条</option>
                <option :value="10">10条</option>
                <option :value="20">20条</option>
                <option :value="50">50条</option>
              </select>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 新增/编辑角色模态框 -->
    <div v-if="showModal" class="modal">
      <div class="modal-content" @click.stop>
        <div class="modal-header">
          <h3 class="modal-title">{{ isEditMode ? '编辑角色' : '添加角色' }}</h3>
          <button class="btn btn-default" @click="closeModal">×</button>
        </div>
        <div class="modal-body">
          <!-- 基本信息分组 -->
          <div class="form-section">
            <h4 class="section-title">
              <span class="section-icon">📝</span>
              基本信息
            </h4>
            <div class="form-row">
              <div class="form-item form-item-half">
                <label class="form-label required">角色名称</label>
                <input type="text" class="input" :class="{ 'input-error': formErrors.name }" v-model="formData.name"
                  placeholder="请输入角色名称" required @input="clearFieldError('name')" />
                <div v-if="formErrors.name" class="error-message">{{ formErrors.name }}</div>
              </div>
              <div class="form-item form-item-half">
                <label class="form-label required">配置名称</label>
                <input type="text" class="input" :class="{ 'input-error': formErrors.configName }"
                  v-model="formData.configName" placeholder="请输入配置名称" required @input="clearFieldError('configName')" />
                <div v-if="formErrors.configName" class="error-message">{{ formErrors.configName }}</div>
              </div>
            </div>
            <div class="form-item">
              <label class="form-label">角色描述</label>
              <textarea class="textarea" :class="{ 'input-error': formErrors.description }"
                v-model="formData.description" placeholder="请输入角色描述" rows="3"
                @input="clearFieldError('description')"></textarea>
              <div v-if="formErrors.description" class="error-message">{{ formErrors.description }}</div>
            </div>
            <div class="form-item">
              <label class="form-label">状态设置</label>
              <div class="checkbox-wrapper">
                <input type="checkbox" id="isActive" v-model="formData.isActive" class="checkbox">
                <label for="isActive" class="checkbox-label">
                  <span class="checkbox-text">启用此角色</span>
                  <span class="checkbox-hint">启用后该角色可被分配给用户</span>
                </label>
              </div>
            </div>
          </div>

          <!-- 字段权限配置分组 -->
          <div class="form-section">
            <h4 class="section-title">
              <span class="section-icon">🔐</span>
              字段权限配置
            </h4>
            <div class="form-item">
              <label class="form-label">字段配置与优先级</label>
              <div class="field-config-container">
                <!-- 动态字段配置列表 -->
                <div class="dynamic-field-list">
                  <div v-for="(fieldItem, index) in dynamicFieldList" :key="index" class="field-config-item"
                    draggable="true" @dragstart="handleDragStart(index)" @dragover="handleDragOver"
                    @drop="handleDrop(index, $event)" :class="{ 'dragging': draggedIndex === index }">
                    <div class="field-item-header">
                      <span class="field-priority">{{ index + 1 }}</span>
                      <span class="drag-handle" title="拖拽调整优先级">⋮⋮</span>
                    </div>
                    <div class="field-item-content">
                      <div class="custom-select-wrapper">
                        <select v-model="fieldItem.field" class="field-select custom-select"
                          @change="onFieldChange(index)">
                          <option value="" disabled>请选择字段</option>
                          <option v-for="field in getAvailableFieldsForIndex(index)" :key="field.id || field.value"
                            :value="field.value">
                            {{ field.chineseName || field.englishName || field.value }}
                          </option>
                        </select>
                        <div class="select-arrow">
                          <svg width="12" height="8" viewBox="0 0 12 8" fill="none">
                            <path d="M1 1L6 6L11 1" stroke="currentColor" stroke-width="2" stroke-linecap="round"
                              stroke-linejoin="round" />
                          </svg>
                        </div>
                      </div>
                    </div>
                    <div class="field-item-actions">
                      <button type="button" class="move-up-btn" @click="moveFieldUp(index)" :disabled="index === 0"
                        title="上移">
                        ↑
                      </button>
                      <button type="button" class="move-down-btn" @click="moveFieldDown(index)"
                        :disabled="index === dynamicFieldList.length - 1" title="下移">
                        ↓
                      </button>
                      <button type="button" class="remove-field-btn" @click="removeField(index)" title="删除">
                        ×
                      </button>
                    </div>
                  </div>

                  <!-- 空状态提示 -->
                  <div v-if="dynamicFieldList.length === 0" class="empty-field-state">
                    <span class="empty-icon">📋</span>
                    <p>暂无字段配置，点击下方按钮添加字段</p>
                  </div>
                </div>

                <!-- 添加字段按钮 -->
                <div class="add-field-section">
                  <button type="button" class="add-field-btn" @click="addNewField"
                    :disabled="getAvailableFieldsForNew().length === 0">
                    <span class="add-icon">+</span>
                    添加字段
                  </button>
                  <span v-if="getAvailableFieldsForNew().length === 0" class="add-disabled-hint">
                    所有字段已添加
                  </span>
                </div>
              </div>
              <div v-if="formErrors.fields" class="error-message">{{ formErrors.fields }}</div>
              <div class="form-hint">
                <span class="hint-icon">💡</span>
                通过下拉框选择字段并设置优先级，数字越小优先级越高。支持拖拽调整优先级顺序。
              </div>
              <div v-if="dynamicFieldList.length > 1" class="drag-tip">
                <span class="hint-icon">🖱️</span>
                提示：可拖动字段项调整优先级顺序
              </div>

            </div>
          </div>

          <!-- 部门分配分组 -->
          <div class="form-section">
            <h4 class="section-title">
              <span class="section-icon">🏢</span>
              部门分配
            </h4>
            <div class="form-item">
              <label class="form-label">可访问部门</label>

              <!-- 部门搜索添加区域 -->
              <div class="department-search-container">
                <input type="text" class="department-search-input" v-model="departmentSearchKeyword"
                  placeholder="搜索并添加部门..." @keyup.enter="addDepartmentFromSearch" @focus="showAllDepartments = true"
                  @blur="hideDropdownWithDelay" />

                <!-- 搜索结果下拉 -->
                <div
                  v-if="(departmentSearchKeyword && filteredDepartmentOptions.length > 0) || (showAllDepartments && departmentOptions.length > 0)"
                  class="search-results">
                  <div
                    v-for="dept in departmentSearchKeyword ? filteredDepartmentOptions.slice(0, 8) : departmentOptions.slice(0, 8)"
                    :key="dept.id || dept.name" class="search-result-item" @mousedown="addDepartment(dept.name)">
                    <span class="dept-icon">🏢</span>
                    <span class="dept-name">{{ dept.name }}</span>
                    <span v-if="dept.englishName && dept.englishName !== dept.name" class="dept-english-name">({{
                      dept.englishName }})</span>
                    <span class="add-indicator">+</span>
                  </div>
                </div>
              </div>

              <!-- 已选部门显示区域 -->
              <div class="selected-departments-container">
                <div v-if="selectedDepartments.length === 0" class="empty-departments">
                  <span class="empty-icon">🏢</span>
                  <span class="empty-text">暂未选择部门，请搜索并添加</span>
                </div>
                <div v-else class="department-tags-grid">
                  <div v-for="(dept, index) in selectedDepartments" :key="dept" class="department-tag-item">
                    <span class="dept-icon">🏢</span>
                    <span class="dept-text">{{ dept }}</span>
                    <button type="button" class="remove-dept-btn" @click="removeDepartment(index)" title="删除部门">
                      ×
                    </button>
                  </div>
                </div>
              </div>

              <div v-if="formErrors.departments" class="error-message">{{ formErrors.departments }}</div>
              <div class="form-hint">
                <span class="hint-icon">💡</span>
                搜索并添加角色可管理的部门，已添加的部门显示在下方
              </div>

            </div>
          </div>



        </div>
        <div class="modal-footer">
          <div v-if="formErrors.server" class="error-message server-error">{{ formErrors.server }}</div>
          <div class="modal-actions">
            <button class="btn btn-default" @click="closeModal" :disabled="isSubmitting">取消</button>
            <button class="btn btn-primary" @click="saveRole" :disabled="isSubmitting">
              <span v-if="isSubmitting">保存中...</span>
              <span v-else>{{ isEditMode ? '更新' : '确定' }}</span>
            </button>
          </div>
        </div>
      </div>
    </div>
  </div>

  <!-- 悬停提示框 -->
  <div v-if="tooltip.show" class="custom-tooltip" :style="{ left: tooltip.x + 'px', top: tooltip.y + 'px' }">
    <div class="tooltip-header">
      <h4>{{ tooltip.title }}</h4>
    </div>
    <div class="tooltip-content">
      <div v-if="tooltip.type === 'fields'" class="tooltip-fields">
        <div v-for="(field, index) in tooltip.fields" :key="index" class="tooltip-field-item">
          <span class="field-priority">{{ index + 1 }}</span>
          <span class="field-name">{{ field }}</span>
        </div>
      </div>
      <div v-if="tooltip.type === 'departments'" class="tooltip-departments">
        <div v-for="(dept, index) in tooltip.departments" :key="index" class="tooltip-dept-item">
          <i class="dept-icon">🏢</i>
          <span class="dept-name">{{ dept }}</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import TopNavigation from '../components/TopNavigation.vue'
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
import { getRoleConfigs, createRoleConfig, updateRoleConfig, deleteRoleConfig } from '../services/roleConfigService'
import { getRoutingFields } from '../services/routeFieldService'
import departmentService from '../services/departmentService'

// 初始化角色数据
const roles = ref([])
const loading = ref(false)
const error = ref('')

// 下拉与拖拽所需状态
const availableFields = ref(['application', 'department', 'status', 'priority', 'assignee', 'createTime', 'updateTime', 'description'])
const departmentOptions = ref([
  { id: 1, name: '研发部' },
  { id: 2, name: '测试部' },
  { id: 3, name: '产品部' },
  { id: 4, name: '运维部' },
  { id: 5, name: '市场部' }
])
const selectedDepartments = ref([])
const departmentSearchKeyword = ref('')
const showAllDepartments = ref(false)
const formErrors = ref({})
const isSubmitting = ref(false)

// 动态字段配置列表
const dynamicFieldList = ref([])
const isDragging = ref(false)

// 悬停提示框状态
const tooltip = ref({
  show: false,
  x: 0,
  y: 0,
  title: '',
  type: '', // 'fields' 或 'departments'
  fields: [],
  departments: []
})

// 拖拽相关状态
const draggedIndex = ref(null)

// 从后端获取角色数据
const fetchRoles = async () => {
  loading.value = true
  error.value = ''
  try {
    console.log('开始获取角色数据...')

    // 构建分页参数
    const params = {
      page: page.value - 1, // 后端通常从0开始计数
      size: pageSize.value
    }

    // 添加搜索参数
    if (searchKeyword.value.trim()) {
      params.search = searchKeyword.value.trim()
    }

    const response = await getRoleConfigs(params)
    console.log('获取角色数据响应:', response)
    if (response && response.code === 200 && response.status === 'success') {
      const roleData = response.data?.content || response.data || []
      totalItems.value = response.data?.totalElements || response.data?.total || roleData.length
      console.log('角色数据获取成功，共', roleData.length, '条，总计', totalItems.value, '条')
      roles.value = roleData.map(role => ({
        id: role.id,
        roleName: role.roleName,
        roleDescription: role.roleDescription,
        configName: role.configName,
        isActive: role.isActive,
        fieldConfig: role.fieldConfig,
        departmentAssignments: role.departmentAssignments,
        fieldPriorities: role.fieldPriorities
      }))
    } else {
      error.value = '获取角色数据失败: ' + (response?.message || '未知错误')
      console.error('获取角色数据失败:', response)
      // 使用模拟数据
      roles.value = [
        {
          id: 1,
          roleName: '系统管理员',
          roleDescription: '负责系统的全面管理和维护',
          configName: 'admin_config',
          isActive: true,
          fieldConfig: '{"fields": ["application", "department"]}',
          departmentAssignments: '研发部,测试部',
          fieldPriorities: 'application,department'
        },
        {
          id: 2,
          roleName: '应用管理员',
          roleDescription: '负责应用的管理和配置',
          configName: 'app_config',
          isActive: true,
          fieldConfig: '{"fields": ["application"]}',
          departmentAssignments: '研发部',
          fieldPriorities: 'application'
        }
      ]
    }
  } catch (err) {
    error.value = '网络错误: ' + err.message
    // 使用模拟数据
    roles.value = [
      {
        id: 1,
        roleName: '系统管理员',
        roleDescription: '负责系统的全面管理和维护',
        configName: 'admin_config',
        isActive: true
      },
      {
        id: 2,
        roleName: '应用管理员',
        roleDescription: '负责应用的管理和配置',
        configName: 'app_config',
        isActive: true
      }
    ]
  } finally {
    loading.value = false
  }
}

// 窗口大小变化处理函数
const handleResize = () => {
  nextTick(() => {
    updateVisibleCounts()
  })
}

// 在组件挂载时获取角色数据
onMounted(async () => {
  await fetchRoles()
  // 清空部门搜索关键字
  departmentSearchKeyword.value = ''

  // 初始化可见标签数量计算
  nextTick(() => {
    updateVisibleCounts()
  })

  // 添加窗口大小变化监听器
  window.addEventListener('resize', handleResize)
})

// 组件卸载时清理监听器
onUnmounted(() => {
  window.removeEventListener('resize', handleResize)
})

// 搜索关键词
const searchKeyword = ref('')

// 模态框相关状态
const showModal = ref(false)
const isEditMode = ref(false)
const currentRoleId = ref(null)
const formData = ref({
  name: '',
  description: ''
})

// 分页数据
const page = ref(1)
const pageSize = ref(10)
const totalItems = ref(0)

// 处理分页大小变化
const onPageSizeChange = () => {
  // 重置到第一页
  page.value = 1;
  fetchRoles();
}

// 计算当前页显示的角色（后端分页）
const paginatedRoles = computed(() => {
  return roles.value
})

// 搜索角色
const searchRoles = () => {
  page.value = 1 // 重置到第一页
  fetchRoles()
}

// 处理页码变化
const onPageChange = (newPage) => {
  page.value = newPage
  fetchRoles()
}

// 加载可选字段
const loadAvailableFields = async () => {
  try {
    const resp = await getRoutingFields()
    if (resp && resp.code === 200 && resp.status === 'success' && Array.isArray(resp.data)) {
      // 存储完整的字段对象，以便在下拉框中显示中文名称
      availableFields.value = resp.data.map(it => {
        if (typeof it === 'object') {
          return {
            id: it.id,
            englishName: it.englishName,
            chineseName: it.chineseName,
            description: it.description,
            // 为了兼容性，添加一个用于比较的唯一标识
            value: it.chineseName || it.englishName || it.id
          }
        }
        return {
          id: it,
          englishName: it,
          chineseName: it,
          description: '',
          value: it
        }
      })
    }
  } catch (e) {
    console.error('获取字段失败', e)
  }
}

// 加载部门列表
const loadDepartments = async () => {
  try {
    const resp = await departmentService.getDepartments()
    if (resp && resp.code === 200 && resp.status === 'success' && Array.isArray(resp.data)) {
      // 确保部门数据格式统一，优先显示中文名称
      departmentOptions.value = resp.data.map(d => {
        if (typeof d === 'object') {
          return {
            id: d.deptId || d.id || d.departmentId,
            name: d.deptName || d.name || d.departmentName || d.deptEnName || String(d.deptId || d.id),
            englishName: d.deptEnName || d.englishName,
            description: d.deptDesc || d.description
          }
        }
        return {
          id: String(d),
          name: String(d),
          englishName: '',
          description: ''
        }
      })
    }
  } catch (e) {
    console.error('获取部门失败', e)
  }
}

// 计算属性：过滤后的字段列表
const filteredAvailableFields = computed(() => {
  if (!fieldSearchKeyword.value) return availableFields.value
  return availableFields.value.filter(field => {
    const keyword = fieldSearchKeyword.value.toLowerCase()
    return (
      (field.chineseName && field.chineseName.toLowerCase().includes(keyword)) ||
      (field.englishName && field.englishName.toLowerCase().includes(keyword)) ||
      (field.value && field.value.toLowerCase().includes(keyword))
    )
  })
})

// 计算属性：过滤后的部门列表
const filteredDepartmentOptions = computed(() => {
  if (!departmentSearchKeyword.value) return departmentOptions.value
  return departmentOptions.value.filter(dept => {
    const keyword = departmentSearchKeyword.value.toLowerCase()
    return (
      (dept.name && dept.name.toLowerCase().includes(keyword)) ||
      (dept.englishName && dept.englishName.toLowerCase().includes(keyword)) ||
      (dept.description && dept.description.toLowerCase().includes(keyword))
    )
  })
})

// 全选字段方法
const toggleAllFields = () => {
  if (selectedFields.value.length === availableFields.value.length) {
    selectedFields.value = []
  } else {
    selectedFields.value = availableFields.value.map(field => field.value)
  }
}

// 全选部门方法
const toggleAllDepartments = () => {
  if (selectedDepartments.value.length === departmentOptions.value.length) {
    selectedDepartments.value = []
  } else {
    selectedDepartments.value = departmentOptions.value.map(dept => dept.name)
  }
}

// 从搜索框添加部门
const addDepartmentFromSearch = () => {
  if (departmentSearchKeyword.value.trim()) {
    const keyword = departmentSearchKeyword.value.trim()
    // 检查是否已存在
    if (!selectedDepartments.value.includes(keyword)) {
      selectedDepartments.value.push(keyword)
    }
    departmentSearchKeyword.value = ''
  }
}

// 添加部门
const addDepartment = (deptName) => {
  if (deptName && !selectedDepartments.value.includes(deptName)) {
    selectedDepartments.value.push(deptName)
  }
}

// 删除部门
const removeDepartment = (index) => {
  selectedDepartments.value.splice(index, 1)
}

// 延迟隐藏下拉框
const hideDropdownWithDelay = () => {
  setTimeout(() => {
    showAllDepartments.value = false
  }, 200)
}

// 从优先级列表中移除字段
const removeFromPriority = (index) => {
  fieldPrioritiesList.value.splice(index, 1)
}

// 表单验证方法
const validateForm = () => {
  const errors = {}

  // 验证角色名称
  if (!formData.value.name || formData.value.name.trim() === '') {
    errors.name = '角色名称不能为空'
  } else if (formData.value.name.length < 2) {
    errors.name = '角色名称至少需要2个字符'
  } else if (formData.value.name.length > 50) {
    errors.name = '角色名称不能超过50个字符'
  }

  // 验证配置名称
  if (!formData.value.configName || formData.value.configName.trim() === '') {
    errors.configName = '配置名称不能为空'
  } else if (formData.value.configName.length < 2) {
    errors.configName = '配置名称至少需要2个字符'
  } else if (formData.value.configName.length > 50) {
    errors.configName = '配置名称不能超过50个字符'
  }

  // 验证角色描述长度
  if (formData.value.description && formData.value.description.length > 200) {
    errors.description = '角色描述不能超过200个字符'
  }

  // 验证字段配置
  const validFields = dynamicFieldList.value.filter(item => item.field && item.field.trim() !== '')
  if (validFields.length === 0) {
    errors.fields = '请至少选择一个字段配置'
  }

  // 验证部门分配
  if (selectedDepartments.value.length === 0) {
    errors.departments = '请至少选择一个部门'
  }

  formErrors.value = errors
  return Object.keys(errors).length === 0
}

// 清除特定字段的错误
const clearFieldError = (fieldName) => {
  if (formErrors.value[fieldName]) {
    delete formErrors.value[fieldName]
    formErrors.value = { ...formErrors.value }
  }
}

// 清除所有错误
const clearAllErrors = () => {
  formErrors.value = {}
}

// 构造提交数据的辅助函数
const buildSubmitData = () => {
  // 提取有效的字段（非空）
  const validFields = dynamicFieldList.value
    .filter(item => item.field && item.field.trim() !== '')
    .map(item => item.field)

  // 按优先级顺序排列的字段列表
  const prioritizedFields = dynamicFieldList.value
    .filter(item => item.field && item.field.trim() !== '')
    .sort((a, b) => a.priority - b.priority)
    .map(item => item.field)

  // 构造部门分配数据，包含部门id和name
  const departmentAssignmentsData = {
    departments: selectedDepartments.value.map(deptName => {
      // 根据部门名称查找对应的部门信息
      const deptInfo = departmentOptions.value.find(dept => dept.name === deptName)
      return {
        id: deptInfo ? deptInfo.id : null,
        name: deptName
      }
    })
  }

  return {
    roleName: formData.value.name,
    roleDescription: formData.value.description,
    configName: formData.value.configName,
    isActive: formData.value.isActive,
    fieldConfig: JSON.stringify({ fields: validFields }),
    departmentAssignments: JSON.stringify(departmentAssignmentsData),
    fieldPriorities: JSON.stringify(prioritizedFields)
  }
}

// 测试数据构造函数 - 演示如何从弹窗数据生成符合后端要求的格式
const testDataConstruction = () => {
  // 模拟用户在弹窗中填写的数据
  const mockFormData = {
    name: '系统管理员',
    description: '负责系统整体管理',
    configName: 'admin_config',
    isActive: true
  }

  const mockDynamicFields = [
    { field: 'application', priority: 1 },
    { field: 'department', priority: 2 }
  ]

  const mockSelectedDepartments = ['开发一部', '产品部']

  // 模拟部门选项数据
  const mockDepartmentOptions = [
    { id: 1, name: '开发一部' },
    { id: 3, name: '产品部' }
  ]

  // 构造部门分配数据，包含部门id和name
  const departmentAssignmentsData = {
    departments: mockSelectedDepartments.map(deptName => {
      const deptInfo = mockDepartmentOptions.find(dept => dept.name === deptName)
      return {
        id: deptInfo ? deptInfo.id : null,
        name: deptName
      }
    })
  }

  // 构造最终提交的数据格式
  const submitData = {
    roleName: mockFormData.name,
    roleDescription: mockFormData.description,
    configName: mockFormData.configName,
    isActive: mockFormData.isActive,
    fieldConfig: JSON.stringify({
      fields: mockDynamicFields.map(item => item.field)
    }),
    departmentAssignments: JSON.stringify(departmentAssignmentsData),
    fieldPriorities: JSON.stringify(
      mockDynamicFields
        .sort((a, b) => a.priority - b.priority)
        .map(item => item.field)
    )
  }

  console.log('构造的提交数据:', submitData)
  console.log('部门分配格式示例:', JSON.stringify(departmentAssignmentsData, null, 2))
  return submitData
}

// 拖拽排序方法
const handleDragStart = (index) => {
  draggedIndex.value = index
  isDragging.value = true
}

const handleDragOver = (e) => {
  e.preventDefault()
}

const handleDrop = (targetIndex, e) => {
  e.preventDefault()

  if (draggedIndex.value === null || draggedIndex.value === targetIndex) {
    draggedIndex.value = null
    isDragging.value = false
    return
  }

  // 创建新的字段列表
  const newFieldList = [...dynamicFieldList.value]
  // 移除拖动的字段
  const [draggedItem] = newFieldList.splice(draggedIndex.value, 1)
  // 在目标位置插入
  newFieldList.splice(targetIndex, 0, draggedItem)

  // 更新优先级
  newFieldList.forEach((item, index) => {
    item.priority = index + 1
  })

  // 更新字段列表
  dynamicFieldList.value = newFieldList

  // 重置拖拽状态
  draggedIndex.value = null
  isDragging.value = false
}

// 显示新增模态框
const showAddModal = async () => {
  isEditMode.value = false
  currentRoleId.value = null
  formData.value = {
    name: '',
    description: '',
    configName: '',
    isActive: true,
    fieldConfig: '',
    departmentAssignments: '',
    fieldPriorities: ''
  }
  // 重置选择
  selectedDepartments.value = []
  dynamicFieldList.value = []
  // 清空搜索关键字
  departmentSearchKeyword.value = ''

  // 先加载可选项，确保数据完整
  await Promise.all([
    loadAvailableFields(),
    loadDepartments()
  ])

  showModal.value = true
}

// 显示编辑模态框
const showEditModal = async (role) => {
  isEditMode.value = true
  currentRoleId.value = role.id
  formData.value = {
    name: role.roleName,
    description: role.roleDescription,
    configName: role.configName || '',
    isActive: role.isActive !== undefined ? role.isActive : true,
    fieldConfig: role.fieldConfig || '',
    departmentAssignments: role.departmentAssignments || '',
    fieldPriorities: role.fieldPriorities || ''
  }

  // 清空搜索关键字
  departmentSearchKeyword.value = ''

  // 先加载可选项，确保数据完整
  await Promise.all([
    loadAvailableFields(),
    loadDepartments()
  ])

  // 解析已有配置并转换为动态字段列表
  const fields = getFieldsFromConfig(role.fieldConfig)
  const priorities = getPrioritiesFromString(role.fieldPriorities)

  // 构建动态字段列表，优先使用优先级顺序
  dynamicFieldList.value = []

  // 辅助函数：根据字段名找到匹配的字段对象并返回其value
  const findMatchingFieldValue = (fieldName) => {
    const matchedField = availableFields.value.find(f =>
      f.value === fieldName ||
      f.chineseName === fieldName ||
      f.englishName === fieldName ||
      f.id === fieldName
    )
    return matchedField ? matchedField.value : fieldName
  }

  if (priorities.length > 0) {
    priorities.forEach((field, index) => {
      // 验证字段是否在可用字段列表中
      const fieldExists = availableFields.value.some(f =>
        f.value === field || f.chineseName === field || f.englishName === field || f.id === field
      )
      if (fieldExists) {
        dynamicFieldList.value.push({
          field: findMatchingFieldValue(field),
          priority: index + 1
        })
      }
    })
    // 添加未在优先级中的字段
    fields.forEach(field => {
      if (!priorities.includes(field)) {
        const fieldExists = availableFields.value.some(f =>
          f.value === field || f.chineseName === field || f.englishName === field || f.id === field
        )
        if (fieldExists) {
          dynamicFieldList.value.push({
            field: findMatchingFieldValue(field),
            priority: dynamicFieldList.value.length + 1
          })
        }
      }
    })
  } else {
    // 如果没有优先级信息，直接使用字段列表
    fields.forEach((field, index) => {
      const fieldExists = availableFields.value.some(f =>
        f.value === field || f.chineseName === field || f.englishName === field || f.id === field
      )
      if (fieldExists) {
        dynamicFieldList.value.push({
          field: findMatchingFieldValue(field),
          priority: index + 1
        })
      }
    })
  }

  selectedDepartments.value = getDepartmentsFromString(role.departmentAssignments)
  showModal.value = true
}

// 关闭模态框
const closeModal = () => {
  showModal.value = false
}

// 保存角色
const saveRole = async () => {
  // 清除之前的错误
  clearAllErrors()

  // 表单验证
  if (!validateForm()) {
    return
  }

  isSubmitting.value = true

  // 检查角色名称是否已存在（编辑时排除当前角色）
  const isNameExists = roles.value.some(role =>
    role.roleName === formData.value.name && role.id !== currentRoleId.value
  )

  if (isNameExists) {
    formErrors.value.roleName = '角色名称已存在'
    isSubmitting.value = false
    return
  }

  // 构造提交数据
  let roleData
  try {
    roleData = buildSubmitData()
  } catch (e) {
    console.error('保存前组装数据失败', e)
    formErrors.value.server = '数据组装失败'
    isSubmitting.value = false
    return
  }

  try {
    if (isEditMode.value) {
      // 更新角色
      const response = await updateRoleConfig(currentRoleId.value, roleData)
      console.log('更新角色响应:', response)
      if (response && (response.code === 200 || response.status === 'success' || response.success)) {
        showMessage('角色更新成功', 'success')
        // 重新获取角色列表
        await fetchRoles()
      } else {
        const errorMsg = response?.message || response?.error || response?.msg || '未知错误'
        formErrors.value.server = '角色更新失败: ' + errorMsg
        console.error('角色更新失败详情:', response)
        return
      }
    } else {
      // 新增角色
      const response = await createRoleConfig(roleData)
      console.log('创建角色响应:', response)
      if (response && (response.code === 200 || response.status === 'success' || response.success)) {
        showMessage('角色创建成功', 'success')
        // 重新获取角色列表
        await fetchRoles()
      } else {
        const errorMsg = response?.message || response?.error || response?.msg || '未知错误'
        formErrors.value.server = '角色创建失败: ' + errorMsg
        console.error('角色创建失败详情:', response)
        return
      }
    }
    closeModal()
  } catch (err) {
    formErrors.value.server = '网络错误: ' + err.message
  } finally {
    isSubmitting.value = false
  }
}

// 删除角色
const deleteRole = async (id) => {
  // 检查是否有默认角色或系统关键角色不能删除
  const role = roles.value.find(r => r.id === id)
  if (role && (role.roleName === '系统管理员' || role.roleName === '普通用户')) {
    showMessage('系统默认角色不能删除', 'error')
    return
  }

  if (confirm('确定要删除该角色吗？')) {
    loading.value = true
    try {
      const response = await deleteRoleConfig(id)
      if (response.code === 200 && response.status === 'success') {
        showMessage('角色删除成功', 'success')
        // 重新获取角色列表
        await fetchRoles()
      } else {
        showMessage('角色删除失败: ' + (response.message || '未知错误'), 'error')
      }
    } catch (err) {
      showMessage('网络错误: ' + err.message, 'error')
    } finally {
      loading.value = false
    }
  }
}

// 解析字段配置的辅助函数
const getFieldsFromConfig = (fieldConfig) => {
  if (!fieldConfig) return []
  try {
    // 如果是字符串，尝试解析为JSON
    if (typeof fieldConfig === 'string') {
      const parsed = JSON.parse(fieldConfig)
      return Array.isArray(parsed?.fields) ? parsed.fields : (Array.isArray(parsed) ? parsed : [])
    }
    // 如果已经是对象
    if (typeof fieldConfig === 'object') {
      return Array.isArray(fieldConfig?.fields) ? fieldConfig.fields : (Array.isArray(fieldConfig) ? fieldConfig : [])
    }
    return []
  } catch (e) {
    // 如果JSON解析失败，尝试按逗号分割
    if (typeof fieldConfig === 'string') {
      return fieldConfig.split(',').map(s => s.trim()).filter(Boolean)
    }
    return []
  }
}

// 解析部门分配的辅助函数（支持JSON格式）
const getDepartmentsFromString = (departmentAssignments) => {
  if (!departmentAssignments) return []
  try {
    // 如果是字符串，先尝试解析为JSON
    if (typeof departmentAssignments === 'string') {
      // 尝试JSON解析
      try {
        const parsed = JSON.parse(departmentAssignments)
        // 新格式：{"departments": [{"id": 101, "name": "开发一部"}, {"id": 102, "name": "产品部"}]}
        if (typeof parsed === 'object' && parsed.departments && Array.isArray(parsed.departments)) {
          return parsed.departments.map(dept => {
            if (typeof dept === 'object' && dept.name) {
              return dept.name
            }
            return typeof dept === 'object' ? (dept.departmentName || dept.id || String(dept)) : String(dept)
          })
        }
        // 旧格式：直接是数组
        if (Array.isArray(parsed)) {
          return parsed.map(dept => typeof dept === 'object' ? (dept.name || dept.departmentName || dept.id || String(dept)) : String(dept))
        }
      } catch (jsonError) {
        // JSON解析失败，按逗号分割
        return departmentAssignments.split(',').map(s => s.trim()).filter(Boolean)
      }
    }
    // 如果已经是数组
    if (Array.isArray(departmentAssignments)) {
      return departmentAssignments.map(dept => typeof dept === 'object' ? (dept.name || dept.departmentName || dept.id || String(dept)) : String(dept))
    }
    // 如果是对象
    if (typeof departmentAssignments === 'object') {
      if (departmentAssignments.departments && Array.isArray(departmentAssignments.departments)) {
        return departmentAssignments.departments.map(dept => {
          if (typeof dept === 'object' && dept.name) {
            return dept.name
          }
          return typeof dept === 'object' ? (dept.departmentName || dept.id || String(dept)) : String(dept)
        })
      }
      return departmentAssignments.departments ? getDepartmentsFromString(departmentAssignments.departments) : []
    }
    return []
  } catch (e) {
    return []
  }
}

// 动态计算可显示的部门数量（基于容器宽度）
const visibleDepartmentCounts = ref({})

// 动态计算可显示的字段数量（基于容器宽度）
const visibleFieldCounts = ref({})

// 计算可显示的部门列表
const getVisibleDepartments = (role) => {
  const allDepartments = getDepartmentsFromString(role.departmentAssignments)
  const maxVisible = visibleDepartmentCounts.value[role.id] || 3
  return allDepartments.slice(0, maxVisible)
}

// 判断是否需要显示省略指示器
const shouldShowMoreIndicator = (role) => {
  const allDepartments = getDepartmentsFromString(role.departmentAssignments)
  const maxVisible = visibleDepartmentCounts.value[role.id] || 3
  return allDepartments.length > maxVisible
}

// 获取隐藏的部门数量
const getHiddenDepartmentCount = (role) => {
  const allDepartments = getDepartmentsFromString(role.departmentAssignments)
  const maxVisible = visibleDepartmentCounts.value[role.id] || 3
  return Math.max(0, allDepartments.length - maxVisible)
}

// 计算可显示的字段列表
const getVisibleFields = (role) => {
  const allFields = getPrioritiesFromString(role.fieldPriorities).length > 0
    ? getPrioritiesFromString(role.fieldPriorities)
    : getFieldsFromConfig(role.fieldConfig)
  const maxVisible = visibleFieldCounts.value[role.id] || 1
  return allFields.slice(0, maxVisible)
}

// 判断是否需要显示字段省略指示器
const shouldShowFieldMoreIndicator = (role) => {
  const allFields = getPrioritiesFromString(role.fieldPriorities).length > 0
    ? getPrioritiesFromString(role.fieldPriorities)
    : getFieldsFromConfig(role.fieldConfig)
  const maxVisible = visibleFieldCounts.value[role.id] || 3
  return allFields.length > maxVisible
}

// 获取隐藏的字段数量
const getHiddenFieldCount = (role) => {
  const allFields = getPrioritiesFromString(role.fieldPriorities).length > 0
    ? getPrioritiesFromString(role.fieldPriorities)
    : getFieldsFromConfig(role.fieldConfig)
  const maxVisible = visibleFieldCounts.value[role.id] || 3
  return Math.max(0, allFields.length - maxVisible)
}

// 计算部门容器可容纳的标签数量（响应式）
const calculateDepartmentVisibleCount = (roleId) => {
  const container = document.querySelector(`.department-tags`)
  if (!container) return 3

  const containerWidth = container.offsetWidth
  if (containerWidth <= 0) return 3

  // 根据屏幕尺寸动态调整标签宽度和最大数量
  const screenWidth = window.innerWidth
  let estimatedTagWidth, maxAllowed

  if (screenWidth > 1600) {
    estimatedTagWidth = 70  // 超大屏幕：标签更紧凑
    maxAllowed = 6
  } else if (screenWidth > 1200) {
    estimatedTagWidth = 75  // 大屏幕
    maxAllowed = 5
  } else if (screenWidth > 900) {
    estimatedTagWidth = 80  // 中等屏幕
    maxAllowed = 4
  } else if (screenWidth > 600) {
    estimatedTagWidth = 85  // 小屏幕
    maxAllowed = 3
  } else {
    estimatedTagWidth = 90  // 移动端：标签更宽
    maxAllowed = 2
  }

  const reservedWidth = 60
  const availableWidth = containerWidth - reservedWidth

  const maxVisible = Math.floor(availableWidth / estimatedTagWidth)
  return Math.max(1, Math.min(maxVisible, maxAllowed))
}

// 计算字段容器可容纳的标签数量（响应式）
const calculateFieldVisibleCount = (roleId) => {
  const container = document.querySelector(`[ref="fieldTags-${roleId}"]`)
  if (!container) return 3

  const containerWidth = container.offsetWidth
  if (containerWidth <= 0) return 3

  // 根据屏幕尺寸动态调整标签宽度和最大数量
  const screenWidth = window.innerWidth
  let estimatedTagWidth, maxAllowed

  if (screenWidth > 1600) {
    estimatedTagWidth = 70  // 超大屏幕：标签更紧凑
    maxAllowed = 6
  } else if (screenWidth > 1200) {
    estimatedTagWidth = 75  // 大屏幕
    maxAllowed = 5
  } else if (screenWidth > 900) {
    estimatedTagWidth = 80  // 中等屏幕
    maxAllowed = 4
  } else if (screenWidth > 600) {
    estimatedTagWidth = 85  // 小屏幕
    maxAllowed = 3
  } else {
    estimatedTagWidth = 90  // 移动端：标签更宽
    maxAllowed = 2
  }

  const reservedWidth = 60
  const availableWidth = containerWidth - reservedWidth

  const maxVisible = Math.floor(availableWidth / estimatedTagWidth)
  return Math.max(1, Math.min(maxVisible, maxAllowed))
}

// 更新所有角色的可见标签数量
const updateVisibleCounts = () => {
  roles.value.forEach(role => {
    // 部门和字段都使用相同的简单估算逻辑
    const deptCount = calculateDepartmentVisibleCount(role.id)
    visibleDepartmentCounts.value[role.id] = deptCount

    const fieldCount = calculateFieldVisibleCount(role.id)
    visibleFieldCounts.value[role.id] = fieldCount
  })
}

// 解析字段优先级的辅助函数（支持JSON格式）
const getPrioritiesFromString = (fieldPriorities) => {
  if (!fieldPriorities) return []
  try {
    // 如果是字符串，先尝试解析为JSON
    if (typeof fieldPriorities === 'string') {
      try {
        const parsed = JSON.parse(fieldPriorities)
        if (Array.isArray(parsed)) {
          return parsed.map(item => typeof item === 'object' ? (item.field || item.name || item.fieldName || String(item)) : String(item))
        }
        if (typeof parsed === 'object' && parsed.priorities) {
          return Array.isArray(parsed.priorities) ? parsed.priorities.map(item => typeof item === 'object' ? (item.field || item.name || item.fieldName || String(item)) : String(item)) : []
        }
      } catch (jsonError) {
        // JSON解析失败，按逗号分割
        return fieldPriorities.split(',').map(s => s.trim()).filter(Boolean)
      }
    }
    // 如果已经是数组
    if (Array.isArray(fieldPriorities)) {
      return fieldPriorities.map(item => typeof item === 'object' ? (item.field || item.name || item.fieldName || String(item)) : String(item))
    }
    // 如果是对象
    if (typeof fieldPriorities === 'object') {
      return fieldPriorities.priorities ? getPrioritiesFromString(fieldPriorities.priorities) : []
    }
    return []
  } catch (e) {
    return []
  }
}

// 动态字段列表相关方法
// 获取指定索引位置可用的字段选项（排除已选择的字段）
const getAvailableFieldsForIndex = (currentIndex) => {
  const selectedFields = dynamicFieldList.value
    .map((item, index) => index !== currentIndex ? item.field : null)
    .filter(field => field && field !== '')
  return availableFields.value.filter(field => !selectedFields.includes(field.value))
}

// 获取新增字段时可用的选项
const getAvailableFieldsForNew = () => {
  const selectedFields = dynamicFieldList.value
    .map(item => item.field)
    .filter(field => field && field !== '')
  return availableFields.value.filter(field => !selectedFields.includes(field.value))
}

// 添加新字段
const addNewField = () => {
  if (getAvailableFieldsForNew().length > 0) {
    dynamicFieldList.value.push({
      field: '',
      priority: dynamicFieldList.value.length + 1
    })
  }
}

// 移除字段
const removeField = (index) => {
  dynamicFieldList.value.splice(index, 1)
  // 重新计算优先级
  dynamicFieldList.value.forEach((item, idx) => {
    item.priority = idx + 1
  })
}

// 上移字段
const moveFieldUp = (index) => {
  if (index > 0) {
    const temp = dynamicFieldList.value[index]
    dynamicFieldList.value[index] = dynamicFieldList.value[index - 1]
    dynamicFieldList.value[index - 1] = temp
    // 重新计算优先级
    dynamicFieldList.value.forEach((item, idx) => {
      item.priority = idx + 1
    })
  }
}

// 下移字段
const moveFieldDown = (index) => {
  if (index < dynamicFieldList.value.length - 1) {
    const temp = dynamicFieldList.value[index]
    dynamicFieldList.value[index] = dynamicFieldList.value[index + 1]
    dynamicFieldList.value[index + 1] = temp
    // 重新计算优先级
    dynamicFieldList.value.forEach((item, idx) => {
      item.priority = idx + 1
    })
  }
}

// 字段选择变化时的处理
const onFieldChange = (index) => {
  // 可以在这里添加额外的逻辑，比如验证等
  console.log(`字段 ${index} 已更改为:`, dynamicFieldList.value[index].field)
}

// 悬停提示相关方法
const showFieldTooltip = (event, role) => {
  const allFields = getFieldsFromConfig(role.fieldConfig)
  const priorities = getPrioritiesFromString(role.fieldPriorities)

  // 如果有优先级信息，按优先级排序显示
  let displayFields = []
  if (priorities.length > 0) {
    displayFields = priorities
  } else {
    displayFields = allFields
  }

  tooltip.value = {
    show: true,
    x: event.pageX + 10,
    y: event.pageY - 10,
    title: `字段配置 (共${allFields.length}个)`,
    type: 'fields',
    fields: displayFields,
    departments: []
  }
}

const showDepartmentTooltip = (event, role) => {
  const allDepartments = getDepartmentsFromString(role.departmentAssignments)

  tooltip.value = {
    show: true,
    x: event.pageX + 10,
    y: event.pageY - 10,
    title: `部门分配 (共${allDepartments.length}个)`,
    type: 'departments',
    fields: [],
    departments: allDepartments
  }
}

const hideTooltip = () => {
  tooltip.value.show = false
}

// 消息提示函数
const showMessage = (message, type = 'info') => {
  // 创建消息元素
  const msgElement = document.createElement('div')
  msgElement.className = `message message-${type}`
  msgElement.textContent = message

  // 添加到body
  document.body.appendChild(msgElement)

  // 3秒后移除
  setTimeout(() => {
    msgElement.style.opacity = '0'
    setTimeout(() => {
      document.body.removeChild(msgElement)
    }, 300)
  }, 3000)
}

// 暴露给开发者工具使用的函数
window.testRoleDataConstruction = testDataConstruction

</script>

<style scoped>
.role-definition {
  width: 100%;
}

.page-header {
  margin-bottom: var(--spacing-xl);
  display: flex;
  align-items: center;
  gap: var(--spacing-md);
}

.page-header h2 {
  font-size: var(--font-size-xl);
  font-weight: 600;
  color: var(--text-primary);
  margin: 0;
}

/* 为必填字段添加样式 */
.form-label.required::after {
  content: " *";
  color: #ff4d4f;
}

/* 继承全局样式 */
.card {
  background-color: var(--bg-white);
  border-radius: var(--border-radius-md);
  box-shadow: var(--shadow-base);
  overflow: hidden;
  transition: box-shadow 0.3s ease;
}

.card:hover {
  box-shadow: var(--shadow-md);
}

.toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--spacing-lg);
  border-bottom: 1px solid var(--border-base);
  flex-wrap: wrap;
  gap: var(--spacing-lg);
}

.search-container {
  display: flex;
  gap: var(--spacing-sm);
  align-items: center;
  flex: 1;
  min-width: 280px;
}

/* 角色卡片容器 - 自适应布局 */
.roles-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(380px, 1fr));
  gap: 24px;
  padding: 24px;
}

/* 角色卡片样式 */
.role-card {
  background: var(--bg-white, #ffffff);
  border: 1px solid var(--border-base, #e5e7eb);
  border-radius: 12px;
  padding: 24px;
  transition: all 0.3s ease;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
  position: relative;
  overflow: hidden;
  min-height: 280px;
  display: flex;
  flex-direction: column;
}

.role-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.12);
  border-color: var(--primary-color, #667eea);
}

/* 角色头部 */
.role-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 16px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border-light, #f0f0f0);
}

.role-title-section {
  flex: 1;
  min-width: 0;
}

.role-name {
  margin: 0 0 8px 0;
  font-size: 18px;
  font-weight: 600;
  color: var(--text-primary, #333);
  line-height: 1.3;
  word-break: break-word;
}

.config-name {
  font-size: 12px;
  color: var(--text-secondary, #666);
  background: var(--bg-light, #f8f9fa);
  padding: 4px 8px;
  border-radius: 6px;
  font-style: italic;
  display: inline-block;
  max-width: 100%;
  word-break: break-word;
}

.role-header-right {
  display: flex;
  align-items: center;
  gap: 12px;
}

.role-status {
  display: flex;
  align-items: center;
}

.role-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* 角色内容 */
.role-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.role-description-section,
.field-config-section,
.department-section {
  background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
  border: 1px solid var(--border-light, #e5e7eb);
  border-radius: 8px;
  padding: 16px;
  transition: all 0.3s ease;
  flex: 1;
}

.role-description-section:hover,
.field-config-section:hover,
.department-section:hover {
  border-color: var(--primary-color, #667eea);
  box-shadow: 0 2px 8px rgba(102, 126, 234, 0.15);
  background: linear-gradient(135deg, #f0f4ff 0%, #ffffff 100%);
}

.section-title {
  font-size: 12px;
  color: var(--text-secondary, #6b7280);
  margin-bottom: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border-light, #e5e7eb);
  position: relative;
}

.section-title::after {
  content: '';
  position: absolute;
  bottom: -1px;
  left: 0;
  width: 24px;
  height: 2px;
  background: var(--primary-color, #667eea);
  transition: width 0.3s ease;
}

.section-title:hover::after {
  width: 48px;
}

.role-description {
  font-size: 14px;
  color: var(--text-regular, #555);
  line-height: 1.5;
  background: var(--bg-white, #ffffff);
  border: 1px solid var(--border-light, #e9ecef);
  border-radius: 6px;
  padding: 12px;
  transition: all 0.3s ease;
  word-break: break-word;
  min-height: 40px;
}

.role-description:hover {
  border-color: var(--primary-color, #667eea);
  box-shadow: 0 2px 4px rgba(102, 126, 234, 0.1);
}

/* 角色操作按钮 */
.role-actions {
  display: flex;
  gap: 10px;
  padding-top: 12px;
  border-top: 1px solid #f0f0f0;
}

.edit-btn,
.delete-btn {
  background: none;
  border: none;
  cursor: pointer;
  padding: 8px;
  border-radius: 6px;
  transition: background-color 0.2s ease;
  font-size: 18px;
}

.edit-btn:hover {
  background-color: #e3f2fd;
}

.delete-btn:hover {
  background-color: #ffebee;
}

/* 空状态样式 */
.empty-state {
  text-align: center;
  padding: 80px 20px;
  color: #999;
  background: #f8f9fa;
  border-radius: 12px;
  margin: 20px 0;
}

.empty-state::before {
  content: "👤";
  font-size: 64px;
  opacity: 0.6;
  display: block;
  margin-bottom: 16px;
}

.empty-state::after {
  content: "暂无角色数据，点击上方按钮添加角色";
  display: block;
  font-size: 14px;
  color: #666;
  margin-top: 8px;
}

.form-item {
  margin-bottom: var(--spacing-lg);
  transition: all 0.3s ease;
}

.form-item:focus-within {
  transform: translateX(5px);
}

.form-label {
  display: block;
  margin-bottom: 8px;
  font-weight: 600;
  color: #374151;
  font-size: 14px;
  position: relative;
}

.form-label.required::after {
  content: '*';
  color: #ef4444;
  margin-left: 4px;
  font-weight: bold;
}

.input {
  width: 100%;
  padding: 12px 16px;
  border: 2px solid #e5e7eb;
  border-radius: 8px;
  font-size: 14px;
  transition: all 0.3s ease;
  background: #ffffff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.input:focus {
  border-color: #667eea;
  box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1), 0 1px 3px rgba(0, 0, 0, 0.1);
  outline: none;
  transform: translateY(-1px);
}

.input:hover {
  border-color: #d1d5db;
}

.input-error {
  border-color: #ef4444 !important;
  box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1) !important;
}

/* 文本域样式增强 */
.textarea {
  width: 100%;
  padding: 12px 16px;
  border: 2px solid #e5e7eb;
  border-radius: 8px;
  font-size: 14px;
  font-family: inherit;
  resize: vertical;
  transition: all 0.3s ease;
  min-height: 80px;
  background: #ffffff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.textarea:focus {
  border-color: #667eea;
  box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1), 0 1px 3px rgba(0, 0, 0, 0.1);
  outline: none;
  transform: translateY(-1px);
}

.textarea:hover {
  border-color: #d1d5db;
}

/* 旧的表格显示样式已移除，使用下方的新样式 */

.priority-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.priority-item {
  font-size: 12px;
  color: var(--text-secondary);
  white-space: nowrap;
}

.empty-value {
  color: var(--text-placeholder, #bfbfbf);
  font-style: italic;
  font-size: 12px;
  padding: 8px 12px;
  background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
  border: 2px dashed #e5e7eb;
  border-radius: 8px;
  text-align: center;
  transition: all 0.3s ease;
}

.empty-value:hover {
  border-color: #d1d5db;
  background: linear-gradient(135deg, #f3f4f6 0%, #ffffff 100%);
}

.status-badge {
  display: inline-block;
  padding: 6px 12px;
  border-radius: 6px;
  font-size: 14px;
  font-weight: 500;
}

.status-active {
  background-color: var(--success-color-light, #f6ffed);
  color: var(--success-color, #52c41a);
}

.status-inactive {
  background-color: var(--error-color-light, #fff2f0);
  color: var(--error-color, #ff4d4f);
}

/* 按钮样式增强 */
.btn {
  transition: all 0.3s ease;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 12px 24px;
  border-radius: 8px;
  font-weight: 600;
  font-size: 14px;
  border: 2px solid transparent;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}

.btn::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
  transition: left 0.5s;
}

.btn:hover::before {
  left: 100%;
}

.btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.btn:active {
  transform: translateY(0);
}

.btn-primary {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: #ffffff;
  border-color: #667eea;
}

.btn-primary:hover {
  background: linear-gradient(135deg, #5a67d8 0%, #6b46c1 100%);
  box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
}

.btn-default {
  background: #ffffff;
  color: #6b7280;
  border-color: #d1d5db;
}

.btn-default:hover {
  background: #f9fafb;
  border-color: #9ca3af;
  color: #374151;
}

.btn-danger {
  background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
  color: #ffffff;
  border-color: #ef4444;
}

.btn-danger:hover {
  background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%);
  box-shadow: 0 4px 12px rgba(239, 68, 68, 0.4);
}

.btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  transform: none !important;
  box-shadow: none !important;
}

.btn:disabled::before {
  display: none;
}

/* 模态框动画增强 */
.modal {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(135deg, rgba(0, 0, 0, 0.4) 0%, rgba(0, 0, 0, 0.6) 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  backdrop-filter: blur(8px);
  animation: modalBackdropFadeIn 0.3s ease;
}

@keyframes modalBackdropFadeIn {
  from {
    opacity: 0;
    backdrop-filter: blur(0px);
  }

  to {
    opacity: 1;
    backdrop-filter: blur(8px);
  }
}

.modal-content {
  background: linear-gradient(145deg, #ffffff 0%, #f8f9fa 100%);
  border-radius: 16px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15), 0 8px 25px rgba(0, 0, 0, 0.1);
  width: 85%;
  max-width: 480px;
  max-height: 85vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  animation: modalFadeIn 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
  border: 1px solid rgba(255, 255, 255, 0.2);
}

@keyframes modalFadeIn {
  from {
    opacity: 0;
    transform: translateY(-30px) scale(0.95);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.modal-header {
  padding: 20px 24px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border-bottom: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
  position: relative;
  overflow: hidden;
}

.modal-header::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(45deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.05) 100%);
  pointer-events: none;
}

.modal-title {
  font-size: 20px;
  font-weight: 600;
  color: #ffffff;
  margin: 0;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
  position: relative;
  z-index: 1;
}

.modal-header .btn {
  background: rgba(255, 255, 255, 0.2);
  border: 1px solid rgba(255, 255, 255, 0.3);
  color: #ffffff;
  border-radius: 50%;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  font-weight: bold;
  transition: all 0.3s ease;
  position: relative;
  z-index: 1;
}

.modal-header .btn:hover {
  background: rgba(255, 255, 255, 0.3);
  transform: scale(1.1);
}

.modal-body {
  padding: 24px;
  overflow-y: auto;
  flex: 1;
  background: #ffffff;
  position: relative;
}

.modal-body::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: linear-gradient(90deg, #667eea 0%, #764ba2 50%, #667eea 100%);
  background-size: 200% 100%;
  animation: shimmer 3s ease-in-out infinite;
}

@keyframes shimmer {

  0%,
  100% {
    background-position: 200% 0;
  }

  50% {
    background-position: -200% 0;
  }
}

.modal-footer {
  padding: 20px 24px;
  background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
  border-top: 2px solid #e5e7eb;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}

.modal-actions {
  display: flex;
  gap: 12px;
  align-items: center;
}

.server-error {
  flex: 1;
  margin: 0;
}

/* 消息提示样式增强 */
.message {
  position: fixed;
  top: 80px;
  right: var(--spacing-xl);
  padding: var(--spacing-md) var(--spacing-lg);
  border-radius: var(--border-radius-md);
  color: #ffffff;
  font-size: var(--font-size-base);
  font-weight: 500;
  box-shadow: var(--shadow-lg);
  z-index: 1000;
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-sm);
  animation: slideIn 0.3s ease;
}

@keyframes slideIn {
  from {
    transform: translateX(100%);
    opacity: 0;
  }

  to {
    transform: translateX(0);
    opacity: 1;
  }
}

.message-success {
  background-color: var(--success-color);
}

.message-error {
  background-color: var(--error-color);
}

/* 响应式调整 */
@media (max-width: 1200px) {
  .roles-grid {
    grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
    gap: 20px;
    padding: 20px;
  }
}

@media (max-width: 768px) {
  .toolbar {
    flex-direction: column;
    align-items: stretch;
  }

  .search-container {
    width: 100%;
  }

  .roles-grid {
    grid-template-columns: 1fr;
    gap: 16px;
    padding: 16px;
  }

  .role-card {
    padding: 20px;
    min-height: 240px;
  }

  .role-name {
    font-size: 16px;
  }

  .modal-content {
    width: 95%;
    margin: 20px;
  }

  .message {
    right: var(--spacing-md);
    left: var(--spacing-md);
  }
}

@media (max-width: 480px) {
  .roles-grid {
    padding: 12px;
    gap: 12px;
  }

  .role-card {
    padding: 16px;
    min-height: 200px;
  }

  .role-name {
    font-size: 15px;
  }

  .config-name {
    font-size: 11px;
  }

  .section-title {
    font-size: 11px;
  }

  .field-tag,
  .department-tag {
    font-size: 11px;
    padding: 4px 8px;
  }
}

/* 下拉选择样式 */
.select {
  width: 100%;
  padding: 12px 16px;
  border: 2px solid #e5e7eb;
  border-radius: 8px;
  background: #ffffff;
  font-size: 14px;
  line-height: 1.4;
  min-height: 44px;
  transition: all 0.3s ease;
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.select:focus {
  border-color: #667eea;
  box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1), 0 1px 3px rgba(0, 0, 0, 0.1);
  outline: none;
  transform: translateY(-1px);
}

.select:hover {
  border-color: #d1d5db;
}

.select[multiple] {
  min-height: 100px;
}

/* 表单提示 */
.form-hint {
  margin-top: 6px;
  color: var(--text-secondary);
  font-size: var(--font-size-sm);
}

/* 表单分组样式 */
.form-section {
  margin-bottom: 32px;
  border: none;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
  background: #ffffff;
  transition: all 0.3s ease;
}

.form-section:hover {
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
  transform: translateY(-2px);
}

.section-title {
  display: flex;
  align-items: center;
  margin: 0;
  padding: 16px 20px;
  background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
  border-bottom: 2px solid #e8ecef;
  font-size: 16px;
  font-weight: 600;
  color: #495057;
  position: relative;
  overflow: hidden;
}

.section-title::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 4px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

.section-icon {
  margin-right: 12px;
  font-size: 18px;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.1));
}

.form-section .form-item {
  margin: 20px 24px;
}

.form-section .form-item:last-child {
  margin-bottom: 24px;
}

/* 表单行布局 */
.form-row {
  display: flex;
  gap: 20px;
  margin: 20px 24px;
}

.form-item-half {
  flex: 1;
  margin: 0 !important;
}

/* 复选框样式优化 */
.checkbox-wrapper {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 16px;
  background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
  border-radius: 8px;
  border: 2px solid #e5e7eb;
  transition: all 0.3s ease;
}

.checkbox-wrapper:hover {
  border-color: #667eea;
  background: linear-gradient(135deg, #f0f4ff 0%, #ffffff 100%);
}

.checkbox {
  width: 18px;
  height: 18px;
  margin-top: 2px;
  accent-color: #667eea;
  cursor: pointer;
}

.checkbox-label {
  display: flex;
  flex-direction: column;
  cursor: pointer;
  flex: 1;
}

.checkbox-text {
  font-weight: 600;
  color: #374151;
  font-size: 14px;
}

.checkbox-hint {
  font-size: 12px;
  color: #6b7280;
  margin-top: 4px;
  line-height: 1.4;
}

/* 增强的选择器样式 */
.enhanced-select-wrapper {
  border: 1px solid #e1e5e9;
  border-radius: 6px;
  background: white;
}

.select-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-bottom: 1px solid #f0f0f0;
  background: #f8f9fa;
}

.search-input {
  flex: 1;
  padding: 6px 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 12px;
}

.select-all-btn {
  padding: 6px 12px;
  background: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  font-size: 12px;
  cursor: pointer;
  transition: background-color 0.2s;
}

.select-all-btn:hover {
  background: #0056b3;
}

.select-options {
  max-height: 200px;
  overflow-y: auto;
  padding: 4px;
}

.option-item {
  display: flex;
  align-items: center;
  padding: 8px 12px;
  cursor: pointer;
  border-radius: 4px;
  transition: background-color 0.2s;
}

.option-item:hover {
  background: #f8f9fa;
}

.option-checkbox {
  margin-right: 8px;
}

.option-text {
  flex: 1;
  font-size: 14px;
}

/* 优先级容器样式 */
.priority-container {
  min-height: 120px;
  border: 1px solid #e1e5e9;
  border-radius: 6px;
  background: #fafbfc;
}

.empty-priority {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 120px;
  color: #6c757d;
  text-align: center;
}

.empty-icon {
  font-size: 24px;
  margin-bottom: 8px;
}

.empty-priority p {
  margin: 0;
  font-size: 14px;
}

/* 增强的拖拽列表样式 */
.enhanced-dnd-list {
  list-style: none;
  padding: 8px;
  margin: 0;
}

.enhanced-dnd-item {
  display: flex;
  align-items: center;
  padding: 12px;
  margin-bottom: 4px;
  background: white;
  border: 1px solid #e1e5e9;
  border-radius: 6px;
  cursor: move;
  transition: all 0.2s ease;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.enhanced-dnd-item:hover {
  background: #f8f9fa;
  border-color: #007bff;
  transform: translateY(-1px);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}

.enhanced-dnd-item.drag-over {
  background: #e3f2fd;
  border-color: #2196f3;
  transform: scale(1.02);
}

.priority-number {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  background: #007bff;
  color: white;
  border-radius: 50%;
  font-size: 12px;
  font-weight: bold;
  margin-right: 12px;
}

.drag-handle {
  margin-right: 12px;
  color: #6c757d;
  font-size: 16px;
  cursor: grab;
}

.drag-handle:active {
  cursor: grabbing;
}

.field-name {
  flex: 1;
  font-weight: 500;
  color: #495057;
}

.remove-btn {
  width: 24px;
  height: 24px;
  background: #dc3545;
  color: white;
  border: none;
  border-radius: 50%;
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  transition: background-color 0.2s;
}

.remove-btn:hover {
  background: #c82333;
}

/* 提示样式优化 */
.form-hint {
  display: flex;
  align-items: center;
  margin-top: 6px;
  font-size: 12px;
  color: #6c757d;
  line-height: 1.4;
}

.hint-icon {
  margin-right: 4px;
  font-size: 14px;
}

/* 拖拽提示样式 */
.drag-tip {
  display: flex;
  align-items: center;
  margin-top: 4px;
  font-size: 11px;
  color: #007bff;
  font-style: italic;
  background: rgba(0, 123, 255, 0.1);
  padding: 4px 8px;
  border-radius: 4px;
  border-left: 3px solid #007bff;
}

/* 错误提示样式 */
.error-message {
  color: #dc3545;
  font-size: 12px;
  margin-top: 4px;
  display: flex;
  align-items: center;
  gap: 4px;
}

.error-message::before {
  content: "⚠️";
  font-size: 12px;
}

.input-error {
  border-color: #dc3545 !important;
  box-shadow: 0 0 0 2px rgba(220, 53, 69, 0.2) !important;
}

.server-error {
  background: #f8d7da;
  border: 1px solid #f5c6cb;
  border-radius: 4px;
  padding: 8px 12px;
  margin-bottom: 12px;
  font-size: 14px;
}

.modal-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}

.btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

/* 加载状态样式 */
.btn:disabled .spinner {
  display: inline-block;
  width: 12px;
  height: 12px;
  border: 2px solid transparent;
  border-top: 2px solid currentColor;
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin-right: 4px;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

/* 帮助文档样式 */
.help-documentation {
  margin-top: 8px;
}

.help-details {
  border: 1px solid #e9ecef;
  border-radius: 6px;
  background: #f8f9fa;
  margin-top: 8px;
}

.help-summary {
  padding: 8px 12px;
  cursor: pointer;
  font-weight: 500;
  color: #495057;
  background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
  border-radius: 6px;
  transition: all 0.2s ease;
  user-select: none;
}

.help-summary:hover {
  background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);
  color: #343a40;
}

.help-details[open] .help-summary {
  border-bottom: 1px solid #e9ecef;
  border-radius: 6px 6px 0 0;
  background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
  color: #1976d2;
}

.help-content {
  padding: 12px 16px;
  background: white;
  border-radius: 0 0 6px 6px;
  font-size: 13px;
  line-height: 1.5;
}

.help-content h5 {
  margin: 0 0 8px 0;
  font-size: 14px;
  font-weight: 600;
  color: #343a40;
  border-bottom: 1px solid #e9ecef;
  padding-bottom: 4px;
}

.help-content ul {
  margin: 8px 0;
  padding-left: 16px;
}

.help-content li {
  margin-bottom: 4px;
  color: #495057;
}

.help-content li strong {
  color: #343a40;
  font-weight: 600;
}

.help-content p {
  margin: 8px 0 0 0;
  color: #6c757d;
  font-style: italic;
}

/* 帮助文档动画效果 */
.help-details {
  transition: all 0.3s ease;
}

.help-details[open] {
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

/* 优化的表格显示样式 */
.field-display {
  width: 100%;
  background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
  border: 1px solid #e9ecef;
  border-radius: 8px;
  padding: 12px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
  transition: all 0.3s ease;
  margin-bottom: 8px;
}

.field-display:hover {
  border-color: #28a745;
  box-shadow: 0 2px 8px rgba(40, 167, 69, 0.15);
  background: linear-gradient(135deg, #e8f5e8 0%, #ffffff 100%);
}

.field-tags {
  display: flex;
  flex-wrap: nowrap;
  gap: 6px;
  margin-bottom: 8px;
  overflow: hidden;
  align-items: flex-start;
}

.field-tag {
  background: linear-gradient(135deg, #e0f2fe 0%, #b3e5fc 100%);
  color: #0277bd;
  padding: 6px 12px;
  border-radius: 6px;
  font-size: 12px;
  display: flex;
  align-items: center;
  gap: 6px;
  border: 1px solid #81d4fa;
  transition: all 0.2s ease;
  min-height: 28px;
  justify-content: flex-start;
  flex: 0 1 auto;
  min-width: fit-content;
  width: auto;
}

.field-tag .priority-number {
  background: #1976d2;
  color: white;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: 9px;
  flex-shrink: 0;
}

.field-tag:hover {
  transform: translateY(-1px);
  box-shadow: 0 2px 4px rgba(2, 119, 189, 0.2);
  background: linear-gradient(135deg, #b3e5fc 0%, #81d4fa 100%);
}

.field-icon {
  font-size: 10px;
}

.field-summary {
  font-size: 11px;
  color: var(--text-secondary, #6b7280);
  font-style: italic;
  margin-top: 8px;
  padding: 4px 8px;
  background: var(--bg-light, #f8f9fa);
  border: 1px solid var(--border-light, #e5e7eb);
  border-radius: 4px;
  text-align: right;
  transition: all 0.2s ease;
}

.field-summary:hover {
  background: linear-gradient(135deg, #d1e7dd 0%, #e8f4fd 100%);
  border-color: #007bff;
}

.department-display {
  width: 100%;
  background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
  border: 1px solid #e9ecef;
  border-radius: 8px;
  padding: 12px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
  transition: all 0.3s ease;
  margin-bottom: 8px;
}

.department-display:hover {
  border-color: #ffc107;
  box-shadow: 0 2px 8px rgba(255, 193, 7, 0.15);
  background: linear-gradient(135deg, #fff8e1 0%, #ffffff 100%);
}

.department-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 8px;
  align-items: flex-start;
}

.department-tag {
  background: linear-gradient(135deg, #f3e5f5 0%, #e1bee7 100%);
  color: #7b1fa2;
  padding: 6px 12px;
  border-radius: 6px;
  font-size: 12px;
  display: flex;
  align-items: center;
  gap: 6px;
  border: 1px solid #ce93d8;
  transition: all 0.2s ease;
  min-height: 28px;
  justify-content: flex-start;
  flex: 0 1 auto;
  min-width: fit-content;
  width: auto;
}

.department-tag:hover {
  transform: translateY(-1px);
  box-shadow: 0 2px 4px rgba(123, 31, 162, 0.2);
  background: linear-gradient(135deg, #e1bee7 0%, #ce93d8 100%);
}

.dept-icon {
  font-size: 10px;
}

.dept-summary {
  font-size: 11px;
  color: var(--text-secondary, #6b7280);
  font-style: italic;
  margin-top: 8px;
  padding: 4px 8px;
  background: var(--bg-light, #f8f9fa);
  border: 1px solid var(--border-light, #e5e7eb);
  border-radius: 4px;
  text-align: right;
  transition: all 0.2s ease;
}

.dept-summary:hover {
  background: linear-gradient(135deg, #ffeaa7 0%, #fff3cd 100%);
  border-color: #ffc107;
}

.priority-display {
  width: 100%;
  background: transparent;
  border: none;
  border-radius: 0;
  padding: 0;
  box-shadow: none;
}

.priority-list {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-bottom: 8px;
  align-items: flex-start;
}

.priority-item {
  background: linear-gradient(135deg, #fff3e0 0%, #ffcc02 20%);
  color: #f57c00;
  padding: 3px 6px;
  border-radius: 8px;
  font-size: 11px;
  display: flex;
  align-items: center;
  gap: 4px;
  border: 1px solid #ffb74d;
  transition: all 0.2s ease;
  flex: 0 1 auto;
  min-width: fit-content;
  width: auto;
}

/* 响应式媒体查询 */
@media (max-width: 768px) {

  .role-description-section,
  .field-config-section,
  .department-section {
    width: 100%;
    height: 100%;
  }

  .field-tags,
  .department-tags,
  .priority-list {
    gap: 4px;
  }

  .field-tag {
    flex: 0 1 auto;
    min-width: fit-content;
    width: auto;
    font-size: 10px;
    padding: 4px 8px;
  }

  .department-tag {
    flex: 0 1 auto;
    min-width: fit-content;
    width: auto;
    font-size: 10px;
    padding: 4px 8px;
  }

  .priority-item {
    flex: 0 1 auto;
    min-width: fit-content;
    width: auto;
    font-size: 10px;
    padding: 2px 4px;
  }
}

@media (max-width: 480px) {

  .role-description-section,
  .field-config-section,
  .department-section {
    width: 100%;
    height: 100%;
  }

  .field-tag {
    flex: 0 1 auto;
    min-width: fit-content;
    width: auto;
    font-size: 9px;
    padding: 3px 6px;
  }

  .department-tag {
    flex: 0 1 auto;
    min-width: fit-content;
    width: auto;
    font-size: 9px;
    padding: 3px 6px;
  }

  .priority-item {
    flex: 0 1 auto;
    min-width: fit-content;
    width: auto;
    font-size: 9px;
    padding: 2px 4px;
  }
}

.priority-item:hover {
  box-shadow: 0 1px 3px rgba(245, 124, 0, 0.2);
}

.priority-number {
  background: #f57c00;
  color: white;
  border-radius: 50%;
  width: 16px;
  height: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  font-weight: bold;
  flex-shrink: 0;
}

.priority-field {
  flex: 1;
  font-weight: 500;
}

.priority-summary {
  font-size: 10px;
  color: #666;
  font-style: italic;
  margin-top: 8px;
  padding: 6px 10px;
  background: linear-gradient(135deg, #fff3e0 0%, #ffcc02 20%);
  border: 1px solid #ffb74d;
  border-radius: 6px;
  text-align: center;
  transition: all 0.2s ease;
}

.priority-summary:hover {
  background: linear-gradient(135deg, #ffcc02 20%, #fff3e0 100%);
  border-color: #f57c00;
}

.more-indicator {
  background: var(--bg-light, #f5f5f5);
  color: var(--text-secondary, #666);
  padding: 6px 10px;
  border-radius: 6px;
  font-size: 11px;
  border: 1px solid var(--border-light, #ddd);
  cursor: pointer;
  transition: all 0.2s ease;
  font-weight: 500;
  display: inline-flex;
  align-items: center;
}

.more-indicator:hover {
  background: var(--bg-hover, #e5e7eb);
  color: var(--text-primary, #333);
  transform: scale(1.05);
  border-color: var(--primary-color, #667eea);
}

.more-priorities {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 2px;
}

/* 悬停提示框样式 */
.custom-tooltip {
  position: fixed;
  z-index: 9999;
  background: white;
  border: 1px solid #e1e5e9;
  border-radius: 8px;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
  max-width: 320px;
  min-width: 200px;
  pointer-events: none;
  animation: tooltipFadeIn 0.2s ease-out;
}

@keyframes tooltipFadeIn {
  from {
    opacity: 0;
    transform: translateY(-5px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.tooltip-header {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  padding: 12px 16px;
  border-radius: 8px 8px 0 0;
  border-bottom: 1px solid #e1e5e9;
}

.tooltip-header h4 {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
}

.tooltip-content {
  padding: 12px;
  max-height: 300px;
  overflow-y: auto;
}

.tooltip-field-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 0;
  border-bottom: 1px solid #f0f0f0;
}

.tooltip-field-item:last-child {
  border-bottom: none;
}

.tooltip-field-item .field-priority {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: bold;
  flex-shrink: 0;
}

.tooltip-field-item .field-name {
  flex: 1;
  font-size: 13px;
  color: #333;
  font-weight: 500;
}

.tooltip-dept-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 0;
  border-bottom: 1px solid #f0f0f0;
}

.tooltip-dept-item:last-child {
  border-bottom: none;
}

.tooltip-dept-item .dept-icon {
  font-size: 14px;
  flex-shrink: 0;
}

.tooltip-dept-item .dept-name {
  flex: 1;
  font-size: 13px;
  color: #333;
  font-weight: 500;
}

/* 动态字段配置样式 */
.field-config-section {
  margin-bottom: 20px;
}

.field-config-list {
  border: 1px solid #e9ecef;
  border-radius: 8px;
  background: #f8f9fa;
  padding: 16px;
  min-height: 120px;
}

.field-config-item {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px;
  background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
  border: 2px solid #e5e7eb;
  border-radius: 12px;
  margin-bottom: 12px;
  transition: all 0.3s ease;
  cursor: grab;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}

.field-config-item:hover {
  border-color: #667eea;
  box-shadow: 0 4px 16px rgba(102, 126, 234, 0.15);
  transform: translateY(-2px);
  background: linear-gradient(135deg, #ffffff 0%, #f0f4ff 100%);
}

.field-config-item:active {
  cursor: grabbing;
}

.field-config-item.dragging {
  opacity: 0.7;
  transform: rotate(3deg) scale(1.02);
  border: 2px dashed #667eea;
  background: linear-gradient(135deg, rgba(102, 126, 234, 0.1) 0%, rgba(102, 126, 234, 0.05) 100%);
  box-shadow: 0 8px 25px rgba(102, 126, 234, 0.25);
}

.field-config-item[draggable="true"]:hover {
  border: 2px solid #667eea;
  background: linear-gradient(135deg, #f0f4ff 0%, #ffffff 100%);
}

.priority-number {
  background: linear-gradient(135deg, #007bff 0%, #0056b3 100%);
  color: white;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: 12px;
  flex-shrink: 0;
}

.drag-handle {
  cursor: grab;
  color: #6c757d;
  font-size: 16px;
  padding: 4px;
  border-radius: 4px;
  transition: all 0.2s ease;
  user-select: none;
}

.drag-handle:hover {
  background: #e9ecef;
  color: #495057;
  transform: scale(1.1);
}

.drag-handle:active {
  cursor: grabbing;
}

.field-config-item:hover .drag-handle {
  color: #007bff;
}

/* 自定义下拉框样式 */
.custom-select-wrapper {
  position: relative;
  flex: 1;
  min-width: 120px;
}

.custom-select {
  width: 100%;
  padding: 10px 40px 10px 12px;
  border: 2px solid #e5e7eb;
  border-radius: 8px;
  background: #ffffff;
  font-size: 13px;
  color: #374151;
  cursor: pointer;
  transition: all 0.3s ease;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.custom-select:focus {
  border-color: #667eea;
  box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1), 0 1px 3px rgba(0, 0, 0, 0.1);
  outline: none;
  transform: translateY(-1px);
}

.custom-select:hover {
  border-color: #d1d5db;
}

.custom-select option {
  padding: 8px 12px;
  background: #ffffff;
  color: #374151;
}

.custom-select option:hover {
  background: #f3f4f6;
}

.custom-select option:disabled {
  color: #9ca3af;
  font-style: italic;
}

.select-arrow {
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  pointer-events: none;
  color: #6b7280;
  transition: all 0.3s ease;
}

.custom-select-wrapper:hover .select-arrow {
  color: #374151;
}

.custom-select:focus+.select-arrow {
  color: #667eea;
  transform: translateY(-50%) rotate(180deg);
}

.field-select {
  flex: 1;
  min-width: 120px;
}

.field-select select {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid #ced4da;
  border-radius: 4px;
  background: white;
  font-size: 14px;
  transition: border-color 0.2s ease;
}

.field-select select:focus {
  outline: none;
  border-color: #007bff;
  box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
}

/* 字段操作按钮样式 */
.move-up-btn,
.move-down-btn {
  width: 32px;
  height: 32px;
  border: 2px solid #e5e7eb;
  border-radius: 8px;
  background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
  color: #495057;
  cursor: pointer;
  font-size: 14px;
  font-weight: bold;
  transition: all 0.3s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  overflow: hidden;
}

.move-up-btn:hover,
.move-down-btn:hover {
  background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);
  border-color: #adb5bd;
  color: #212529;
  transform: translateY(-1px);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.move-up-btn:disabled,
.move-down-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
  transform: none !important;
  box-shadow: none !important;
  background: #f8f9fa;
  color: #adb5bd;
}

.remove-field-btn {
  background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
  color: white;
  border: 2px solid #ef4444;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.3s ease;
  flex-shrink: 0;
  font-size: 14px;
  font-weight: bold;
}

.remove-field-btn:hover {
  background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%);
  border-color: #dc2626;
  transform: translateY(-1px);
  box-shadow: 0 2px 8px rgba(239, 68, 68, 0.3);
}

.field-item-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}

.add-field-btn {
  background: linear-gradient(135deg, #10b981 0%, #059669 100%);
  color: white;
  border: 2px solid #10b981;
  padding: 12px 20px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  transition: all 0.3s ease;
  font-size: 14px;
  font-weight: 600;
  position: relative;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(16, 185, 129, 0.2);
}

.add-field-btn::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
  transition: left 0.5s ease;
}

.add-field-btn:hover::before {
  left: 100%;
}

.add-field-btn:hover {
  background: linear-gradient(135deg, #059669 0%, #047857 100%);
  border-color: #059669;
  transform: translateY(-2px);
  box-shadow: 0 4px 16px rgba(16, 185, 129, 0.3);
}

.add-field-btn:active {
  transform: translateY(0);
  box-shadow: 0 2px 8px rgba(16, 185, 129, 0.2);
}

.add-field-btn:disabled {
  background: linear-gradient(135deg, #d1d5db 0%, #9ca3af 100%);
  border-color: #d1d5db;
  color: #6b7280;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.add-field-btn:disabled::before {
  display: none;
}

/* 空状态样式 */
.empty-field-state {
  text-align: center;
  padding: 40px 20px;
  background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
  border: 2px dashed #dee2e6;
  border-radius: 12px;
  margin: 20px 0;
}

.empty-field-state .empty-icon {
  font-size: 48px;
  display: block;
  margin-bottom: 16px;
  opacity: 0.6;
}

.empty-field-state p {
  color: #6c757d;
  font-size: 14px;
  margin: 0;
  font-weight: 500;
}

/* 添加字段区域 */
.add-field-section {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 16px;
}

.add-disabled-hint {
  color: #6b7280;
  font-size: 13px;
  font-style: italic;
  background: #f3f4f6;
  padding: 6px 12px;
  border-radius: 6px;
  border: 1px solid #e5e7eb;
}

/* 字段项头部 */
.field-item-header {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 60px;
}

.field-priority {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: bold;
  box-shadow: 0 2px 4px rgba(102, 126, 234, 0.3);
}

.drag-handle {
  color: #9ca3af;
  cursor: grab;
  font-size: 16px;
  transition: color 0.2s ease;
}

.drag-handle:hover {
  color: #6b7280;
}

.field-config-item:active .drag-handle {
  cursor: grabbing;
}

/* 字段项内容 */
.field-item-content {
  flex: 1;
  min-width: 0;
}

.field-config-empty {
  text-align: center;
  color: #6c757d;
  font-style: italic;
  padding: 40px 20px;
}

.field-config-empty i {
  font-size: 48px;
  color: #dee2e6;
  margin-bottom: 12px;
  display: block;
}

.move-buttons {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.move-btn {
  background: #f8f9fa;
  border: 1px solid #dee2e6;
  color: #6c757d;
  width: 24px;
  height: 24px;
  border-radius: 4px;
  display: flex;
}

/* 部门搜索容器 */
.department-search-container {
  position: relative;
  margin-bottom: 16px;
}

.department-search-input {
  width: 100%;
  padding: 12px 16px;
  border: 2px solid #e1e5e9;
  border-radius: 8px;
  font-size: 14px;
  background: #ffffff;
  transition: all 0.3s ease;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}

.department-search-input:focus {
  outline: none;
  border-color: #4f46e5;
  box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
}

.search-results {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: white;
  border: 1px solid #e1e5e9;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  max-height: 200px;
  overflow-y: auto;
  z-index: 1000;
}

.search-result-item {
  padding: 12px 16px;
  cursor: pointer;
  border-bottom: 1px solid #f3f4f6;
  transition: background-color 0.2s ease;
}

.dept-english-name {
  color: #6b7280;
  font-size: 12px;
  margin-left: 4px;
  font-style: italic;
}

.search-result-item:hover {
  background-color: #f8fafc;
}

.search-result-item:last-child {
  border-bottom: none;
}

/* 已选部门容器 */
.selected-departments-container {
  margin-top: 16px;
  padding: 20px;
  border: 2px solid #e5e7eb;
  border-radius: 12px;
  background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  transition: all 0.3s ease;
  min-height: 80px;
}

.selected-departments-container:hover {
  border-color: #d1d5db;
  box-shadow: 0 8px 25px -5px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}

.empty-departments {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 24px;
  text-align: center;
  color: #6b7280;
}

.empty-departments .empty-icon {
  font-size: 32px;
  margin-bottom: 8px;
  opacity: 0.7;
}

.empty-departments .empty-text {
  font-size: 14px;
  font-weight: 500;
  color: #9ca3af;
}

.department-tags-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-start;
}

.department-tag-item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
  color: white;
  border-radius: 20px;
  font-size: 14px;
  font-weight: 500;
  box-shadow: 0 4px 6px -1px rgba(59, 130, 246, 0.3), 0 2px 4px -1px rgba(59, 130, 246, 0.2);
  transition: all 0.2s ease;
  border: 1px solid rgba(255, 255, 255, 0.2);
  position: relative;
  overflow: hidden;
}

.department-tag-item::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
  transition: left 0.5s ease;
}

.department-tag-item:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 15px -3px rgba(59, 130, 246, 0.4), 0 4px 6px -2px rgba(59, 130, 246, 0.3);
}

.department-tag-item:hover::before {
  left: 100%;
}

.dept-icon {
  font-size: 16px;
  opacity: 0.9;
}

.dept-text {
  font-weight: 500;
  letter-spacing: 0.025em;
}

.remove-dept-btn {
  background: rgba(255, 255, 255, 0.2);
  border: none;
  color: white;
  cursor: pointer;
  padding: 0;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  font-weight: bold;
  transition: all 0.2s ease;
  margin-left: 4px;
}

.remove-dept-btn:hover {
  background: rgba(239, 68, 68, 0.9);
  transform: scale(1.1);
  box-shadow: 0 2px 4px rgba(239, 68, 68, 0.3);
}
</style>